/*
 * VU class handles Vector operations.  VU is an acronym for Vector Unit.
 * The Vector Unit handles scalar addition and subtraction of two vectors.
 * 
 * Component registers are First Vector Operand Register, Second Vector
 * Operand Register, Vector Result Register and the Vector Length Register.
 * 
 * Operations use the ALU ( and as a result the SRU due to dependency ).
 * 
 * Vectors are accessed via pointer.  Vector operands are therefore address
 * pointers to contiguous memory locations of length determined by the 
 * Vector Length Register.
 * 
 *  Because vector operations are designed to overwrite the data associated 
 *  with the first vector operand, vector operations will ultimately destroy 
 *  the original vector pointed to by the first vector operand.  The second
 *  vector operand will be preserved.   
 *  
 * */

package cpu.components;

import cpu.datastores.Register16;
import cpu.interfaces.EventListener;

public class VU {
	
	// First Vector Operand Register
	// A pointer to the vector
	// Result Stored back at pointer
	public Register16 VO0;
	
	// Second Vector Operand Register
	// A pointer to the vector
	public Register16 VO1;
	
	// Vector Result Register
	// A pointer to the vector
	// Same as V01
	public Register16 VR;
	
	// Vector Length
	public Register16 VL;
	
	private CPU cpu;
	
	public VU( CPU cpu ) {
		this.cpu = cpu;
		
		VO0 = new Register16();
		VO1 = new Register16();
		VL = new Register16();
		VR = new Register16();
	}
	
	public void add( ) {
		VR.fromRegister( VO0 );
		
		int length = VL.toSignedInteger( );
		
		boolean cc0 = false;
		boolean cc1 = false;

		int vpointer0 = VO0.toSignedInteger( );
		int vpointer1 = VO1.toSignedInteger( );
		
		for( int i = 0; i < length; i++ ) {
			
			
			// Fetch the first operand
			cpu.memoryunit.MAR.fromSignedInteger( vpointer0 );
			cpu.controlunit.updateMemoryAddressIndicator();
			
			cpu.memoryunit.get();
			
			int address0 = cpu.memoryunit.MBR.toSignedInteger( ) + 2 * i;
			
			cpu.memoryunit.MAR.fromSignedInteger( address0 );
			cpu.controlunit.updateMemoryAddressIndicator();			
			
			cpu.memoryunit.get();
			
			cpu.alu.ALO0.fromRegister( cpu.memoryunit.MBR );
			
			int b1 = cpu.memoryunit.MBR.toSignedInteger();
			
			// Fetch the second operand
			cpu.memoryunit.MAR.fromSignedInteger( vpointer1 );
			cpu.controlunit.updateMemoryAddressIndicator();
			
			cpu.memoryunit.get();
			
			int address1 = cpu.memoryunit.MBR.toSignedInteger( ) + 2 * i;

			cpu.memoryunit.MAR.fromSignedInteger( address1 );
			cpu.controlunit.updateMemoryAddressIndicator();
			
			cpu.memoryunit.get();

			cpu.alu.ALO1.fromRegister( cpu.memoryunit.MBR );
			
			int b2 = cpu.memoryunit.MBR.toSignedInteger();
			
			// Apply the operation
			cpu.alu.add( );
			
			// Handle Conditions
			if( cpu.controlunit.CC0.bit( 0 ).value == true )
				cc0 = true;
			if( cpu.controlunit.CC1.bit( 0 ).value == true )
				cc1 = true;
			// Note: no point in early exit because original vector ruined anyway
			
			// Store the result
			cpu.memoryunit.MAR.fromSignedInteger( address0 );
			cpu.controlunit.updateMemoryAddressIndicator();
			
			int x = cpu.alu.ALR.wordLow.toSignedInteger();
			
			cpu.memoryunit.MBR.fromWord( cpu.alu.ALR.wordLow );
			
			cpu.memoryunit.put( );
		}
		cpu.controlunit.cc( ControlUnit.UNDERFLOW, cc0 );
		cpu.controlunit.cc( ControlUnit.OVERFLOW, cc1 );
	}
	
	public void subtract( ) {
		VR.fromRegister( VO0 );
		
		int length = VL.toSignedInteger( );
		
		boolean cc0 = false;
		boolean cc1 = false;

		int vpointer0 = VO0.toSignedInteger( );
		int vpointer1 = VO1.toSignedInteger( );
		
		for( int i = 0; i < length; i++ ) {
			
			
			// Fetch the first operand
			cpu.memoryunit.MAR.fromSignedInteger( vpointer0 );
			cpu.controlunit.updateMemoryAddressIndicator();
			
			cpu.memoryunit.get();
			
			int address0 = cpu.memoryunit.MBR.toSignedInteger( ) + 2 * i;
			
			cpu.memoryunit.MAR.fromSignedInteger( address0 );
			cpu.controlunit.updateMemoryAddressIndicator();			
			
			cpu.memoryunit.get();
			
			cpu.alu.ALO0.fromRegister( cpu.memoryunit.MBR );
			
			int b1 = cpu.memoryunit.MBR.toSignedInteger();
			
			// Fetch the second operand
			cpu.memoryunit.MAR.fromSignedInteger( vpointer1 );
			cpu.controlunit.updateMemoryAddressIndicator();			
			
			cpu.memoryunit.get();
			
			int address1 = cpu.memoryunit.MBR.toSignedInteger( ) + 2 * i;

			cpu.memoryunit.MAR.fromSignedInteger( address1 );
			cpu.controlunit.updateMemoryAddressIndicator();
			
			cpu.memoryunit.get();

			cpu.alu.ALO1.fromRegister( cpu.memoryunit.MBR );
			
			int b2 = cpu.memoryunit.MBR.toSignedInteger();
			
			// Apply the operation
			cpu.alu.subtract( );
			
			// Handle Conditions
			if( cpu.controlunit.CC0.bit( 0 ).value == true )
				cc0 = true;
			if( cpu.controlunit.CC1.bit( 0 ).value == true )
				cc1 = true;
			// Note: no point in early exit because original vector ruined anyway
			
			// Store the result
			cpu.memoryunit.MAR.fromSignedInteger( address0 );
			cpu.controlunit.updateMemoryAddressIndicator();
			
			int x = cpu.alu.ALR.wordLow.toSignedInteger();
			
			cpu.memoryunit.MBR.fromWord( cpu.alu.ALR.wordLow );
			
			cpu.memoryunit.put( );
		}

		cpu.controlunit.cc( ControlUnit.UNDERFLOW, cc0 );
		cpu.controlunit.cc( ControlUnit.OVERFLOW, cc1 );
	}
}
